package com.vonchenchen.renderer;

import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.SurfaceHolder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import static android.graphics.ImageFormat.NV21;
import static android.hardware.Camera.CAMERA_ERROR_EVICTED;
import static android.hardware.Camera.CAMERA_ERROR_SERVER_DIED;
import static android.hardware.Camera.CAMERA_ERROR_UNKNOWN;

/**
 * Created by  on 2021/1/27.
 */
public class VideoCaptureCamera extends VideoCapture implements Camera.PreviewCallback, SurfaceHolder.Callback {
    private static final String TAG = "CAMERA1";
    private static final boolean DEBUG = false;
    protected Camera mCamera;
    protected ReentrantLock mPreviewBufferLock = new ReentrantLock();
    private ReentrantLock mCaptureLock = new ReentrantLock();
    private boolean isCaptureStarted = false;
    private boolean isCaptureRunning = false;
    private boolean isSurfaceReady = false;
    private boolean isFaceDetectionStarted = false;
    private SurfaceHolder mLocalPreview = null;
    private SurfaceTexture mDummySurfaceTexture = null;
    private boolean mOwnsBuffers = false;
    private final int mNumCaptureBuffers = 3;
    private int mExpectedFrameSize = 0;
    private int mCaptureWidth = -1;
    private int mCaptureHeight = -1;
    private int mCaptureFps = -1;
    //private int mCaptureFormat = 17;
    private int mCaptureFormat = NV21;
    private static final long CAMERA_OPEN_REQUEST_INTERVAL = 2000L;
    private HandlerThread mCameraRecoverHandlerThread = null;
    private Handler mHandler = null;
    private final Object mRecoverThreadObjectLock = new Object();
    private Object mObjectLock = new Object();
    private boolean mIsAutoFaceFocusEnabled = false;

    VideoCaptureCamera(Context context, int id, long nativeVideoCaptureDeviceAndroid) {
        super(context, id, nativeVideoCaptureDeviceAndroid);
    }

    protected static Camera.CameraInfo getCameraInfo(int id) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();

        try {
            Camera.getCameraInfo(id, cameraInfo);
            return cameraInfo;
        } catch (RuntimeException var3) {
            Log.e("CAMERA1", "getCameraInfo: Camera.getCameraInfo: ", var3);
            return null;
        }
    }

    static int getNumberOfCameras() {
        return Camera.getNumberOfCameras();
    }

    static String getName(int id) {
        Camera.CameraInfo cameraInfo = getCameraInfo(id);
        return cameraInfo == null ? null : "camera " + id + ", facing " + (cameraInfo.facing == 1 ? "front" : "back");
    }

    static String getCaptureName() {
        return "camera1";
    }

    static int getSensorOrientation(int id) {
        Camera.CameraInfo cameraInfo = getCameraInfo(id);
        return cameraInfo == null ? -1 : cameraInfo.orientation;
    }

    public int UnRegisterNativeHandle() {
        Log.d("CAMERA1", "UnRegisterNativeHandle called");
        synchronized(this.mRecoverThreadObjectLock) {
            this.mNativeVideoCaptureDeviceAndroid = 0L;
            return 0;
        }
    }

    public int allocate() {
        try {
            this.mCamera = Camera.open(this.mId);
        } catch (RuntimeException var2) {
            Log.e("CAMERA1", "allocate: Camera.open: ", var2);
            return -1;
        }

        Camera.CameraInfo cameraInfo = getCameraInfo(this.mId);
        if (cameraInfo == null) {
            this.mCamera.release();
            this.mCamera = null;
            return -2;
        } else {
            if (VideoCapture.fetchCapability(this.mId, this.mContext, getCaptureName()) == null) {
                this.createCapabilities();
            }

            this.mCameraNativeOrientation = cameraInfo.orientation;
            if (this.mNativeVideoCaptureDeviceAndroid != 0L) {
                this.mIsAutoFaceFocusEnabled = this.isAutoFaceFocusEnabled(this.mNativeVideoCaptureDeviceAndroid);
            }

            return 0;
        }
    }

    public int setCaptureFormat(int format) {
        Log.d("CAMERA1", "setCaptureFormat: " + format);
        this.mCaptureFormat = translateToAndroidFormat(format);
        if (this.mCaptureFormat == 0) {
            Log.e("CAMERA1", "setCaptureFormat failed, unkonwn format: " + format);
            return -1;
        } else {
            return 0;
        }
    }

    private int tryStartCapture(int width, int height, int frameRate) {
        if (this.mCamera == null) {
            Log.e("CAMERA1", "Camera not initialized %d" + this.mId);
            return -1;
        } else {
            Log.i("CAMERA1", "tryStartCapture: " + width + "*" + height + ", frameRate: " + frameRate + ", isCaptureRunning: " + this.isCaptureRunning + ", isSurfaceReady: " + this.isSurfaceReady + ", isCaptureStarted: " + this.isCaptureStarted);
            if (!this.isCaptureRunning && this.isCaptureStarted) {
                Camera.Parameters parameters = this.mCamera.getParameters();
                parameters.setPreviewSize(width, height);
                parameters.setPreviewFormat(this.mCaptureFormat);
                parameters.setPreviewFrameRate(frameRate);
                setAdvancedCameraParameters(parameters);
                setDeviceSpecificParameters(parameters);
                mCamera.setParameters(parameters);
                int bufSize = width * height * ImageFormat.getBitsPerPixel(mCaptureFormat) / 8;
                bufSize += 4096;
                byte[] buffer = null;

                for(int i = 0; i < 3; ++i) {
                    buffer = new byte[bufSize];
                    mCamera.addCallbackBuffer(buffer);
                }

                mCamera.setPreviewCallbackWithBuffer(this);
                mOwnsBuffers = true;
                mCamera.setErrorCallback(new Camera.ErrorCallback() {
                    public void onError(int error, Camera camera) {
                        Log.e("CAMERA1", "onError: error code" + error);
                        if (error == CAMERA_ERROR_EVICTED || error == CAMERA_ERROR_SERVER_DIED || error == CAMERA_ERROR_UNKNOWN) {
                            if (mCamera != null) {
                                stopCapture();
                                mCaptureLock.lock();
                                if (mCamera != null) {
                                    mCamera.release();
                                    mCamera = null;
                                }

                                VideoCaptureCamera.this.mCaptureLock.unlock();
                            }

                            synchronized(mRecoverThreadObjectLock) {
                                if (mCameraRecoverHandlerThread == null) {
                                    mCameraRecoverHandlerThread = new HandlerThread("camera-recover-thread");
                                    mCameraRecoverHandlerThread.start();
                                    if (mCameraRecoverHandlerThread != null) {
                                        mHandler = new Handler(VideoCaptureCamera.this.mCameraRecoverHandlerThread.getLooper());
                                    }
                                }

                                if (mHandler != null) {
                                    mHandler.postDelayed(new Runnable() {
                                        public void run() {
                                            synchronized(VideoCaptureCamera.this.mRecoverThreadObjectLock) {
                                                Log.i("CAMERA1", "native handle = " + VideoCaptureCamera.this.mNativeVideoCaptureDeviceAndroid);
                                                if (isForeground() && null == VideoCaptureCamera.this.mCamera && VideoCaptureCamera.this.mNativeVideoCaptureDeviceAndroid != 0L) {
                                                    allocate();
                                                    startCapture(VideoCaptureCamera.this.mCaptureWidth, VideoCaptureCamera.this.mCaptureHeight, VideoCaptureCamera.this.mCaptureFps);
                                                } else {
                                                    if (mHandler != null) {
                                                        mHandler.postDelayed(this, 2000L);
                                                    }

                                                }
                                            }
                                        }
                                    }, 2000L);
                                }
                            }
                        }

                    }
                });
                this.mCamera.startPreview();
                if (this.isAutoFaceFocusSupported()) {
                    this.mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
                        private long mLastFocusedTs;

                        public void onFaceDetection(Camera.Face[] faces, Camera camera) {
                            if (faces != null && faces.length != 0 && camera != null && VideoCaptureCamera.this.mIsAutoFaceFocusEnabled) {
                                if (System.currentTimeMillis() - this.mLastFocusedTs < 3000L) {
                                    if (faces[0].score > 20) {
                                        VideoCaptureCamera.this.notifyCameraFocusAreaChanged(faces[0].rect);
                                    }

                                } else if (faces[0].score <= 50) {
                                    Log.i("CAMERA1", "face score = " + faces[0].score);
                                } else {
                                    try {
                                        List<Camera.Area> focusList = new ArrayList();
                                        Camera.Area firstFace = new Camera.Area(faces[0].rect, 1000);
                                        focusList.add(firstFace);
                                        if (camera.getParameters().getMaxNumFocusAreas() > 0) {
                                            camera.getParameters().setFocusAreas(focusList);
                                        }

                                        if (camera.getParameters().getMaxNumMeteringAreas() > 0) {
                                            camera.getParameters().setMeteringAreas(focusList);
                                        }

                                        VideoCaptureCamera.this.notifyCameraFocusAreaChanged(faces[0].rect);
                                        camera.autoFocus(new Camera.AutoFocusCallback() {
                                            public void onAutoFocus(boolean success, Camera camera) {
                                                Log.d("CAMERA1", "auto face focus called api1 every 3 seconds");

                                                try {
                                                    if (camera != null) {
                                                        camera.cancelAutoFocus();
                                                    }
                                                } catch (RuntimeException var4) {
                                                    Log.w("CAMERA1", "Exception in cancelAutoFocus: " + Log.getStackTraceString(var4));
                                                }

                                            }
                                        });
                                        mLastFocusedTs = System.currentTimeMillis();
                                    } catch (RuntimeException var5) {
                                        Log.w("CAMERA1", "Exception in onFaceDetection callback: " + Log.getStackTraceString(var5));
                                    }

                                }
                            }
                        }
                    });
                    Log.i("CAMERA1", "enable face detection");
                    mCamera.startFaceDetection();
                    isFaceDetectionStarted = true;
                }

                this.mPreviewBufferLock.lock();
                this.mExpectedFrameSize = bufSize;
                this.isCaptureRunning = true;
                this.mPreviewBufferLock.unlock();
                parameters = this.mCamera.getParameters();
                Log.e("CAMERA1", "Params: " + parameters.flatten());
                return 0;
            } else {
                Log.w("CAMERA1", "tryStartCapture return");
                return 0;
            }
        }
    }

    private void notifyCameraFocusAreaChanged(Rect faceRect) {
        boolean isMirror = false;
        if (this.mId == 1) {
            isMirror = true;
        }

        RectF rectF = CoordinatesTransform.normalizedFaceRect(faceRect, 0, isMirror);
        float x = rectF.left;
        float y = rectF.top;
        float width = rectF.width();
        float height = rectF.height();
        Log.d("CAMERA1", "auto face focus left =" + rectF.left + " top = " + rectF.top + " right = " + rectF.right + " bottom = " + rectF.bottom);
        this.NotifyCameraFocusAreaChanged(x, y, width, height, this.mNativeVideoCaptureDeviceAndroid);
    }

    public int setZoom(float zoomValue) {
        int zoomRatio = (int)(zoomValue * 100.0F + 0.5F);
        List<Integer> zoomRatios = this.getZoomRatios();
        if (zoomRatios == null) {
            return -1;
        } else {
            int zoomLevel = 0;

            int maxZoom;
            for(int i = 0; i < zoomRatios.size(); ++i) {
                maxZoom = (Integer)zoomRatios.get(i);
                if (zoomRatio <= maxZoom) {
                    zoomLevel = i;
                    break;
                }
            }

            if (this.mCamera != null) {
                Camera.Parameters parameters = this.getCameraParameters();
                if (this.isZoomSupported(parameters)) {
                    maxZoom = parameters.getMaxZoom();
                    if (zoomLevel > maxZoom) {
                        Log.w("CAMERA1", "zoom value is larger than maxZoom value");
                        return -1;
                    }

                    parameters.setZoom(zoomLevel);
                    this.mCamera.setParameters(parameters);
                }
            }

            return 0;
        }
    }

    public float getMaxZoom() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            int maxZoom = 0;
            if (this.isZoomSupported(parameters)) {
                maxZoom = parameters.getMaxZoom();
            }

            List<Integer> zoomRatios = this.getZoomRatios();
            if (zoomRatios != null && zoomRatios.size() > maxZoom) {
                return (float)(Integer)zoomRatios.get(maxZoom) / 100.0F;
            }
        }

        return -1.0F;
    }

    public int setTorchMode(boolean isTorchOn) {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null) {
                List<String> supportedFlashModes = parameters.getSupportedFlashModes();
                if (supportedFlashModes != null && supportedFlashModes.contains("torch")) {
                    if (isTorchOn) {
                        parameters.setFlashMode("torch");
                    } else {
                        parameters.setFlashMode("off");
                    }

                    this.mCamera.setParameters(parameters);
                    return 0;
                }

                return -1;
            }
        }

        return -2;
    }

    public int setFocus(float x, float y, boolean inPreview) {
        Log.d("CAMERA1", "setFocus called camera api1");
        if (this.mCamera == null) {
            return -1;
        } else if (x >= 0.0F && x <= 1.0F && y >= 0.0F && y <= 1.0F) {
            Rect focusRect = calculateTapArea(x, y, 1.0F);
            Rect meteringRect = calculateTapArea(x, y, 1.5F);
            this.mCamera.cancelAutoFocus();
            Camera.Parameters params = this.getCameraParameters();
            if (params == null) {
                return -1;
            } else {
                ArrayList meteringAreas;
                if (params.getMaxNumFocusAreas() > 0) {
                    meteringAreas = new ArrayList();
                    meteringAreas.add(new Camera.Area(focusRect, 800));
                    params.setFocusAreas(meteringAreas);
                } else {
                    Log.i("CAMERA1", "focus areas not supported");
                }

                if (params.getMaxNumMeteringAreas() > 0) {
                    meteringAreas = new ArrayList();
                    meteringAreas.add(new Camera.Area(meteringRect, 800));
                    params.setMeteringAreas(meteringAreas);
                } else {
                    Log.i("CAMERA1", "metering areas not supported");
                }

                final String currentFocusMode = params.getFocusMode();
                if (isSupported("macro", params.getSupportedFocusModes())) {
                    params.setFocusMode("macro");
                    synchronized(this.mObjectLock) {
                        this.mCamera.setParameters(params);
                    }
                } else {
                    Log.i("focus", "FOCUS_MODE_MACRO is not supported");
                }

                this.mCamera.autoFocus(new Camera.AutoFocusCallback() {
                    public void onAutoFocus(boolean success, Camera camera) {
                        Camera.Parameters params = camera.getParameters();
                        params.setFocusMode(currentFocusMode);
                        synchronized(VideoCaptureCamera.this.mObjectLock) {
                            camera.setParameters(params);
                        }
                    }
                });
                if (this.mNativeVideoCaptureDeviceAndroid != 0L) {
                    this.NotifyCameraFocusAreaChanged(x, y, 0.0F, 0.0F, this.mNativeVideoCaptureDeviceAndroid);
                }

                return 0;
            }
        } else {
            Log.e("CAMERA1", "set focus unreasonable inputs");
            return -1;
        }
    }

    public int setExposure(float x, float y, boolean inPreview) {
        Log.d("CAMERA1", "setExposure called camera api1 x = " + x + " y = " + y);
        if (this.mCamera == null) {
            return -1;
        } else if (x >= 0.0F && x <= 1.0F && y >= 0.0F && y <= 1.0F) {
            Rect meteringRect = calculateTapArea(x, y, 1.5F);
            if (this.mCamera != null) {
                Camera.Parameters params = this.getCameraParameters();
                if (params == null) {
                    return -1;
                }

                if (params.getMaxNumMeteringAreas() > 0) {
                    List<Camera.Area> meteringAreas = new ArrayList();
                    meteringAreas.add(new Camera.Area(meteringRect, 800));
                    params.setMeteringAreas(meteringAreas);
                } else {
                    Log.i("CAMERA1", "metering areas not supported");
                }

                this.mCamera.setParameters(params);
                this.mCamera.startPreview();
            }

            if (this.mNativeVideoCaptureDeviceAndroid != 0L) {
                this.NotifyCameraExposureAreaChanged(x, y, 0.0F, 0.0F, this.mNativeVideoCaptureDeviceAndroid);
            }

            return 0;
        } else {
            Log.e("CAMERA1", "set exposure unreasonable inputs");
            return -1;
        }
    }

    public int setAutoFaceFocus(boolean enable) {
        this.mIsAutoFaceFocusEnabled = enable;
        return 0;
    }

    public int startCapture(int width, int height, int frameRate) {
        if (this.mCamera == null) {
            Log.e("CAMERA1", "startCapture: camera is null!!");
            return -1;
        } else {
            int res = 0;
            //this.mLocalPreview = ViERenderer.GetLocalRenderer();
            if (mLocalPreview != null) {
                if (this.mLocalPreview.getSurface() != null && this.mLocalPreview.getSurface().isValid()) {
                    this.surfaceCreated(this.mLocalPreview);
                }

                this.mLocalPreview.addCallback(this);
            } else {
                this.mCaptureLock.lock();

                try {
                    this.mDummySurfaceTexture = new SurfaceTexture(42);
                    this.mCamera.setPreviewTexture(this.mDummySurfaceTexture);
                } catch (Exception var18) {
                    Log.e("CAMERA1", "failed to startPreview, invalid surfaceTexture!");
                    this.mDummySurfaceTexture = null;
                    res = -1;
                } finally {
                    this.mCaptureLock.unlock();
                    if (res != 0) {
                        return res;
                    }

                }
            }

            this.mCaptureLock.lock();
            this.isCaptureStarted = true;
            this.mCaptureWidth = width;
            this.mCaptureHeight = height;
            this.mCaptureFps = frameRate;

            try {
                res = this.tryStartCapture(width, height, frameRate);
            } catch (Throwable var16) {
                Log.e("CAMERA1", "try start capture failed " + var16);
                res = -1;
            } finally {
                this.mCaptureLock.unlock();
            }

            return res;
        }
    }

    public int stopCapture() {
        if (!this.isCaptureStarted) {
            Log.w("CAMERA1", "already stop capture");
            return 0;
        } else {
            try {
                if (this.isFaceDetectionStarted) {
                    this.mCamera.stopFaceDetection();
                    this.mCamera.setFaceDetectionListener(null);
                    this.isFaceDetectionStarted = false;
                }
            } catch (RuntimeException var3) {
                Log.e("CAMERA1", "Failed to stop face detection", var3);
            }

            try {
                this.mPreviewBufferLock.lock();
                this.isCaptureRunning = false;
                this.mCamera.stopPreview();
                this.mPreviewBufferLock.unlock();
                this.mCamera.setErrorCallback((Camera.ErrorCallback)null);
                this.mCamera.setPreviewCallbackWithBuffer((Camera.PreviewCallback)null);
            } catch (RuntimeException var2) {
                Log.e("CAMERA1", "Failed to stop camera", var2);
                return -1;
            }

            this.isCaptureStarted = false;
            return 0;
        }
    }

    public boolean isTorchSupported() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null) {
                return isSupported("torch", parameters.getSupportedFlashModes());
            }
        }

        return false;
    }

    public boolean isFocusSupported() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null) {
                boolean isFocusSupported = parameters.getMaxNumFocusAreas() > 0 && isSupported("auto", parameters.getSupportedFocusModes());
                return isFocusSupported;
            }
        }

        return false;
    }

    public boolean isExposureSupported() {
        boolean isExposureSupported = false;
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null) {
                isExposureSupported = parameters.getMaxNumMeteringAreas() > 0;
            }
        }

        return isExposureSupported;
    }

    public boolean isZoomSupported() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null) {
                return parameters.isZoomSupported();
            }
        }

        return false;
    }

    public boolean isAutoFaceFocusSupported() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (parameters != null && parameters.getMaxNumDetectedFaces() > 0 && parameters.getMaxNumFocusAreas() > 0 && isSupported("auto", parameters.getSupportedFocusModes())) {
                return true;
            }
        }

        return false;
    }

    public void deallocate() {
        if (this.mCamera != null) {
            synchronized(this.mRecoverThreadObjectLock) {
                this.mNativeVideoCaptureDeviceAndroid = 0L;
                this.stopCapture();
                this.mCaptureLock.lock();
                if (this.mCamera != null) {
                    this.mCamera.release();
                    this.mCamera = null;
                }

                this.mCaptureLock.unlock();
                if (this.mHandler != null) {
                    this.mHandler.removeCallbacksAndMessages((Object)null);
                }

                if (this.mCameraRecoverHandlerThread != null) {
                    this.mCameraRecoverHandlerThread.quit();
                    this.mCameraRecoverHandlerThread = null;
                    this.mHandler = null;
                }

            }
        }
    }

    public void onPreviewFrame(byte[] data, Camera camera) {
        try {
            this.mPreviewBufferLock.lock();
            if (data != null && this.isCaptureRunning) {
                if (data.length == this.mExpectedFrameSize && this.mNativeVideoCaptureDeviceAndroid != 0L) {
                    this.ProvideCameraFrame(data, this.mExpectedFrameSize, this.mNativeVideoCaptureDeviceAndroid);
                    return;
                }

                if (this.mNativeVideoCaptureDeviceAndroid == 0L) {
                    Log.w("CAMERA1", "warning mNativeVideoCaptureDeviceAndroid = 0, error");
                }

                return;
            }
        } finally {
            this.mPreviewBufferLock.unlock();
            if (camera != null && this.isCaptureRunning) {
                camera.addCallbackBuffer(data);
            }

        }

    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    public void surfaceCreated(SurfaceHolder holder) {
        this.mCaptureLock.lock();

        try {
            if (this.mCamera != null) {
                this.mCamera.stopPreview();
                this.mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException var3) {
            Log.e("CAMERA1", "Failed to set preview surface!", var3);
        } catch (RuntimeException var4) {
            Log.e("CAMERA1", "Failed to stop preview!", var4);
        }

        this.mCaptureLock.unlock();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        this.mCaptureLock.lock();

        try {
            if (this.mCamera != null) {
                this.mCamera.setPreviewDisplay((SurfaceHolder)null);
            }
        } catch (IOException var3) {
            Log.e("CAMERA1", "Failed to clear preview surface!", var3);
        }

        this.mCaptureLock.unlock();
    }

    private static boolean isSupported(String value, List<String> supported) {
        return supported == null ? false : supported.indexOf(value) >= 0;
    }

    private void setAdvancedCameraParameters(Camera.Parameters parameters) {
        String flashMode = "off";
        if (isSupported(flashMode, parameters.getSupportedFlashModes())) {
            Log.i("CAMERA1", "AgoraVideo set flash mode = FLASH_MODE_OFF");
            parameters.setFlashMode(flashMode);
        }

        String whiteBalance = "auto";
        if (isSupported(whiteBalance, parameters.getSupportedWhiteBalance())) {
            Log.i("CAMERA1", "AgoraVideo set white blance = WHITE_BALANCE_AUTO");
            parameters.setWhiteBalance(whiteBalance);
        }

        String focusMode = "continuous-video";
        if (isSupported(focusMode, parameters.getSupportedFocusModes())) {
            Log.i("CAMERA1", "AgoraVideo set Focus mode = FOCUS_MODE_CONTINUOUS_VIDEO");
            parameters.setFocusMode(focusMode);
        }

        String antibandingSupported = "auto";
        if (isSupported(antibandingSupported, parameters.getSupportedAntibanding())) {
            Log.i("CAMERA1", "AgoraVideo set anti-banding = ANTIBANDING_AUTO");
            parameters.setAntibanding(antibandingSupported);
        }

        String sceneMode = "auto";
        if (isSupported(sceneMode, parameters.getSupportedSceneModes())) {
            Log.i("CAMERA1", "AgoraVideo set sence mode = " + sceneMode);
            if (parameters.getSceneMode() != sceneMode) {
                parameters.setSceneMode(sceneMode);
            }
        }

    }

    private void setDeviceSpecificParameters(Camera.Parameters parameters) {
        String device = DeviceUtils.getDeviceId();
        String cpuName = DeviceUtils.getCpuName();
        String cpuABI = DeviceUtils.getCpuABI();
        int cpuCores = DeviceUtils.getNumberOfCPUCores();
        int maxFreq = DeviceUtils.getCPUMaxFreqKHz();
        Log.i("CAMERA1", "Current Device: " + device);
        Log.i("CAMERA1", "CPU name: " + cpuName + ", with " + cpuCores + " cores, arch: " + cpuABI + ", max Freq: " + maxFreq);
        if (device.contains("xiaomi/mi note")) {
            Log.i("CAMERA1", "set MiNote config");
            parameters.set("scene-detect", "on");
            parameters.set("xiaomi-still-beautify-values", "i:3");
            parameters.set("skinToneEnhancement", "enable");
            parameters.set("auto-exposure", "center-weighted");
        }

        if (device.contains("oppo/r7c/r7c")) {
            Log.i("CAMERA1", "set oppo r7c config");
            parameters.set("skinToneEnhancement", 1);
            parameters.set("face-beautify", 100);
            parameters.set("auto-exposure", "center-weighted");
        }

    }

    public Camera.Parameters getCameraParameters() {
        try {
            Camera.Parameters parameters = this.mCamera.getParameters();
            return parameters;
        } catch (RuntimeException var3) {
            Log.e("CAMERA1", "getCameraParameters: Camera.getParameters: ", var3);
            if (this.mCamera != null) {
                this.mCamera.release();
                this.mCamera = null;
            }

            return null;
        }
    }

    public int createCapabilities() {
        String cap = null;
        Camera.Parameters param = this.getCameraParameters();
        if (param != null) {
            String cap_id = "\"id\":" + this.mId + ",";
            String cap_res_header = "\"resolution\":";
            String cap_res_value = "";
            List<Camera.Size> sizes = param.getSupportedPreviewSizes();

            String cap_fps_header;
            for(int i = 0; i < sizes.size(); ++i) {
                int width = ((Camera.Size)sizes.get(i)).width;
                int height = ((Camera.Size)sizes.get(i)).height;
                if (width >= 240 && height >= 240 && (width >= 320 || height >= 320)) {
                    cap_fps_header = "{\"w\":" + width + ",\"h\":" + height + "}";
                    if (!cap_res_value.isEmpty()) {
                        cap_res_value = cap_res_value + "," + cap_fps_header;
                    } else {
                        cap_res_value = cap_fps_header;
                    }
                }
            }

            String cap_fmt_header = "\"format\":";
            String cap_fmt_value = "";
            List<Integer> fmts = param.getSupportedPreviewFormats();
            if (VideoCapture.isEmulator()) {
                fmts.remove(842094169);
            }

            for(int i = 0; i < fmts.size(); ++i) {
                int fmt = translateToEngineFormat((Integer)fmts.get(i));
                if (i != fmts.size() - 1) {
                    cap_fmt_value = cap_fmt_value + fmt + ",";
                } else {
                    cap_fmt_value = cap_fmt_value + fmt;
                }
            }

            cap_fps_header = "\"fps\":";
            String cap_fps_value = "";
            List<Integer> framerates = param.getSupportedPreviewFrameRates();

            for(int i = 0; i < framerates.size(); ++i) {
                int fps = (Integer)framerates.get(i);
                if (i != framerates.size() - 1) {
                    cap_fps_value = cap_fps_value + fps + ",";
                } else {
                    cap_fps_value = cap_fps_value + fps;
                }
            }

            cap = "{" + cap_id + cap_res_header + "[" + cap_res_value + "]," + cap_fmt_header + "[" + cap_fmt_value + "]," + cap_fps_header + "[" + cap_fps_value + "]}";
        }

        cacheCapability(this.mId, this.mContext, cap, getCaptureName());
        return 0;
    }

    private List<Integer> getZoomRatios() {
        if (this.mCamera != null) {
            Camera.Parameters parameters = this.getCameraParameters();
            if (this.isZoomSupported(parameters)) {
                return parameters.getZoomRatios();
            }
        }

        return null;
    }

    private boolean isZoomSupported(Camera.Parameters parameters) {
        if (parameters != null) {
            boolean isZoomSupported = parameters.isZoomSupported();
            if (isZoomSupported) {
                return true;
            } else {
                Log.w("CAMERA1", "camera zoom is not supported ");
                return false;
            }
        } else {
            return false;
        }
    }

    private static Rect calculateTapArea(float x, float y, float coefficient) {
        float focusAreaSize = 300.0F;
        int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
        int centerX = (int)(x * 2000.0F - 1000.0F);
        int centerY = (int)(y * 2000.0F - 1000.0F);
        int halfAreaSize = areaSize / 2;
        RectF rectF = new RectF((float)clamp(centerX - halfAreaSize, -1000, 1000), (float)clamp(centerY - halfAreaSize, -1000, 1000), (float)clamp(centerX + halfAreaSize, -1000, 1000), (float)clamp(centerY + halfAreaSize, -1000, 1000));
        return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
    }

    private static int clamp(int val, int min, int max) {
        return Math.max(min, Math.min(max, val));
    }

    private boolean isForeground() {
        if (this.mContext != null) {
            ActivityManager activityManager = (ActivityManager)this.mContext.getSystemService(Service.ACTIVITY_SERVICE);
            List<ActivityManager.RunningAppProcessInfo> processes = activityManager.getRunningAppProcesses();
            if (processes == null) {
                Log.e("CAMERA1", "List of RunningAppProcessInfo is null");
                return false;
            }

            for(int i = 0; i < processes.size(); ++i) {
                ActivityManager.RunningAppProcessInfo processInfo = (ActivityManager.RunningAppProcessInfo)processes.get(i);
                if (processInfo == null) {
                    Log.e("CAMERA1", "ActivityManager.RunningAppProcessInfo is null");
                } else if (processInfo.processName.equals(this.mContext.getPackageName()) && processInfo.importance == 100) {
                    return true;
                }
            }
        }

        return false;
    }
}